package de.slothsoft.bookmaker;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import de.slothsoft.bookmaker.parse.ParseContext;
import de.slothsoft.bookmaker.parse.WebsiteDescription;
import de.slothsoft.bookmaker.parse.WebsiteDescriptions;
import de.slothsoft.bookmaker.parse.WebsiteParser;
import de.slothsoft.bookmaker.pdf.ITextPdfCreator;
import de.slothsoft.bookmaker.pdf.PdfCreator;
import de.slothsoft.bookmaker.pdf.PdfRequest;

public class Downloader {

    private ProgressMonitor monitor = new SystemOutProgressMonitor();

    public void download(List<String> urls, File targetFolder) throws IOException {
        List<PdfRequest> requests = new ArrayList<>();
        for (String url : urls) {
            requests.addAll(Arrays.asList(createPdfRequests(url)));
        }
        createPdfs(requests, targetFolder);
        this.monitor.setText("Finished.");
    }

    public void download(String url, File targetFolder) throws IOException {
        List<PdfRequest> requests = Arrays.asList(createPdfRequests(url));
        createPdfs(requests, targetFolder);
        this.monitor.setText("Finished.");
    }

    protected PdfRequest[] createPdfRequests(String url) throws IOException {
        WebsiteDescription description = WebsiteDescriptions.find(url);
        if (description == null) {
            throw new IOException("Could not find parser for URL: " + url);
        }
        try (InputStream input = new URL(url).openStream()) {
            ParseContext context = new ParseContext(this.monitor);
            context.setUrl(url);

            WebsiteParser parser = description.createParser(context, input);
            return parser.parse(this.monitor);
        }
    }

    protected void validatePdfRequests(List<PdfRequest> requests) {
        validatePdfNames(requests);
    }

    protected static void validatePdfNames(List<PdfRequest> requests) {
        List<String> names = new ArrayList<>(requests.size());
        for (PdfRequest request : requests) {
            String name = guessName(names, request.getDisplayName());
            request.setDisplayName(name);
            names.add(name);
        }
    }

    private static String guessName(List<String> names, String name) {
        int index = 2;
        String result = name;
        while (names.contains(result)) {
            result = name + ' ' + index++;
        }
        return result;
    }

    protected void createPdfs(List<PdfRequest> requests, File targetFolder) throws IOException {
        validatePdfRequests(requests);
        targetFolder.mkdirs();

        PdfCreator creator = createPdfCreator(targetFolder);
        for (PdfRequest request : requests) {
            creator.createPdf(this.monitor, request);
        }
    }

    protected PdfCreator createPdfCreator(File targetFolder) {
        return new ITextPdfCreator(targetFolder);
    }

    public ProgressMonitor getMonitor() {
        return this.monitor;
    }

    public void setMonitor(ProgressMonitor monitor) {
        this.monitor = monitor;
    }

}
